package com.etnoe.gis.common.domain;


/**
 * Created by Macro on 2018/4/16.
 * Copyright 2018 Guangdong Eastone Century Technology Co.,Ltd.
 * All rights reserved.
 */
//@Description(name = "pointinpoly", value = "_FUNC_(longitude, latitude, polygon) - Returns whether the point is in the polygon (1 means true, 0 means false).", extended = "Example:\n"
//        + "  > SELECT _FUNC_(126.16, 23.68, 125.16,22.68;126.16,23.68;127.16,24.68;128.16,25.68) FROM src LIMIT 1;\n" + "  1")
public class PointInPoly {

    /**
     * 坐标是否在多边形面中(点面求交)，1表示true，0表示false，-1表示异常围栏数据
     * @param lon 坐标经度
     * @param lat 坐标纬度
     * @param polygon 多边形
     * @return
     */
    public String evaluate(double lon, double lat, String polygon){
        String[] poly = polygon.split(";");
        if (poly == null || poly.length < 3) {
           return "-1";
        }
        int size = poly.length;
        if("".equals(poly[size - 1])){
            size = size - 1;
        }

        double maxMinLonLat[] = calMaxMinLonLat(poly, size);
        if(lon < maxMinLonLat[0] || lon > maxMinLonLat[2] || lat < maxMinLonLat[1] || lat > maxMinLonLat[3]){
            return "-1";
        }

        double tmpLon = 0, tmpLat = 0;
        int crossings = 0, j;
        for (int i = 0; i < size; i++) {
            j = i + 1;
            if (size == j) j = 0;

            double pLon1 = tmpLon;
            double pLat1 = tmpLat;
            if(i == 0){
                pLon1 = Double.parseDouble(poly[i].split(",")[0].trim());
                pLat1 = Double.parseDouble(poly[i].split(",")[1].trim());
            }
            double pLon2 = Double.parseDouble(poly[j].split(",")[0].trim());
            double pLat2 = Double.parseDouble(poly[j].split(",")[1].trim());
            // 以下语句判断A点是否在边的两端点的水平平行线之间，在则可能有交点，开始判断交点是否在左射线上
            if (((lat >= pLat1) && (lat < pLat2)) || ((lat >= pLat2) && (lat < pLat1))) {
                if (Math.abs(pLat1 - pLat2) > 0) {
                    // 得到 A点向左射线与边的交点的x坐标：
                    double dLon = pLon1 - ((pLon1 - pLon2) * (pLat1 - lat)) / (pLat1 - pLat2);
                    // 如果交点在A点左侧（说明是做射线与 边的交点），则射线与边的全部交点数加一：
                    if (dLon < lon) {
                        crossings++;
                    }
                }
            }

            tmpLon = pLon2;
            tmpLat = pLat2;
        }
        return (crossings % 2) + "";
    }

    private double[] calMaxMinLonLat(String[] poly, int size){
        double minLon = 0, minLat = 0, maxLon = 0, maxLat = 0;
        double tmpLon = 0, tmpLat = 0;
        for (int i = 0; i < size; i++) {
            if(i == 0){
                minLon = Double.parseDouble(poly[i].split(",")[0].trim());
                minLat = Double.parseDouble(poly[i].split(",")[1].trim());
                maxLon = Double.parseDouble(poly[i].split(",")[0].trim());
                maxLat = Double.parseDouble(poly[i].split(",")[1].trim());
            }
            tmpLon = Double.parseDouble(poly[i].split(",")[0].trim());
            tmpLat = Double.parseDouble(poly[i].split(",")[1].trim());
            if(tmpLon < minLon){
                minLon = tmpLon;
            }
            if(tmpLat < minLat){
                minLat = tmpLat;
            }
            if(tmpLon > maxLon){
                maxLon = tmpLon;
            }
            if(tmpLat > maxLat){
                maxLat = tmpLat;
            }
        }
        return new double[]{minLon, minLat, maxLon, maxLat};
    }

    public static void main(String[] args) {
        PointInPoly poly = new PointInPoly();
        System.out.println(poly.evaluate(113.25726,23.113114,"113.25724,23.113114;113.28874,23.114535;113.255781,23.094325;"));
    }
}